package com.gp.billsrecord.model.room

import android.app.Application
import android.os.Looper
import androidx.lifecycle.LiveData
import androidx.paging.PagingSource
import androidx.room.*
import androidx.sqlite.db.SupportSQLiteDatabase
import com.gp.billsrecord.base.Const
import com.gp.billsrecord.model.data.*
import com.xujichang.base.extensions.Logs
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.lang.RuntimeException

@Database(
    entities = [LogonUser::class, AccountType::class, AccountInfo::class, BillFlowInfo::class, ConsumptionType::class],
    exportSchema = false,
    version = 2
)
/*数据库整体控制的类*/
abstract class AppDatabase : RoomDatabase() {

    abstract fun accountDao(): AccountDao
    abstract fun billFlowDao(): BillFlowDao
    abstract fun consumptionDao(): ConsumptionDao
    abstract fun logonUserDao(): LogonUserDao

    companion object {
        /*默认的账户类型*/
        private val accountTypeInit = listOf(
            AccountType(Const.ACCOUNT_TYPE_START + 1, "现金,", 0L),
            AccountType(Const.ACCOUNT_TYPE_START + 2, "银行卡", 0L),
            AccountType(Const.ACCOUNT_TYPE_START + 3, "信用卡", 0L),
            AccountType(Const.ACCOUNT_TYPE_START + 4, "饭卡", 0L),
            AccountType(Const.ACCOUNT_TYPE_START + 5, "支付宝", 0L),
            AccountType(Const.ACCOUNT_TYPE_START + 6, "微信", 0L),
            AccountType(Const.ACCOUNT_TYPE_START + 7, "公交卡", 0L),
        )

        /*默认的消费类型*/
        private val consumptionTypeInit = listOf(
            ConsumptionType(Const.CONSUMPTION_TYPE_START + 1, "食品", 0L),
            ConsumptionType(Const.CONSUMPTION_TYPE_START + 2, "衣服", 0L),
            ConsumptionType(Const.CONSUMPTION_TYPE_START + 3, "住宿", 0L),
            ConsumptionType(Const.CONSUMPTION_TYPE_START + 4, "打车", 0L),
            ConsumptionType(Const.CONSUMPTION_TYPE_START + 5, "旅游", 0L),
            ConsumptionType(Const.CONSUMPTION_TYPE_START + 6, "游戏", 0L),
            ConsumptionType(Const.CONSUMPTION_TYPE_START + 7, "话费", 0L),
        )

        private var _instance: AppDatabase? = null

        private val instance: AppDatabase
            get() =
                _instance ?: throw RuntimeException("数据库创建失败")

        fun get(application: Application): AppDatabase {
            if (null == _instance) {
                _instance = Room
                    .databaseBuilder(application, AppDatabase::class.java, "db_app")
                    .fallbackToDestructiveMigration()
                    .addCallback(object : Callback() {
                        override fun onCreate(db: SupportSQLiteDatabase) {
                            /*数据库第一次被创建的时候会调用此方法*/
                            Logs.d(
                                "AppDatabase",
                                "onCreate - - isMain:${Looper.getMainLooper() == Looper.myLooper()}"
                            )
                            CoroutineScope(Dispatchers.IO).launch {
                                //添加默认数据
                                instance.accountDao().addTypes(accountTypeInit)
                                instance.consumptionDao().addConsumptionTypes(consumptionTypeInit)
                            }
                        }
                    })
                    .build()
            }
            return instance
        }
    }

}

/*对数据库的操作*/
/**用户表的操作*/
@Dao
interface LogonUserDao {
    /*查询是否有此用户*/
    @Query("SELECT * FROM tbl_logon_user WHERE userName = :nameOrPhone OR userPhone = :nameOrPhone LIMIT 1")
    suspend fun queryNameOrPhone(nameOrPhone: String): LogonUser?

    /*注册*/
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun register(user: LogonUser): Long

    /*获取用户信息*/
    @Query("SELECT * FROM tbl_logon_user WHERE userId=:userId")
    fun observerUserInfo(userId: Long): LiveData<LogonUser>

    /**
     * 更新头像
     */
    @Query("UPDATE tbl_logon_user SET userAvatar = :absolutePath WHERE userId = :userId")
    fun updateAvatar(userId: Long, absolutePath: String)
}

/*操作消费类型数据库*/
@Dao
interface ConsumptionDao {
    /*添加消费类型*/
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun addConsumptionTypes(list: List<ConsumptionType>)

    /*获取消费类型*/
    @Query("SELECT * FROM tbl_consumption_type WHERE userId = :userId OR userId = 0")
    fun observeConsumptionTypes(userId: Long): LiveData<List<ConsumptionType>>
}

/*流水数据库*/
@Dao
interface BillFlowDao {
    /*根据时间和消费类型取流水*/
    @Query("SELECT * FROM tbl_bill_flow WHERE userId=:userId AND (createTime BETWEEN :timeStart AND :timeEnd) AND typeId IN (:types) ")
    fun filterDateAndTag(
        timeStart: Long,
        timeEnd: Long,
        types: List<Long>,
        userId: Long
    ): PagingSource<Int, BillFlowInfo>

    /*只按时间范围取流水数据*/
    @Query("SELECT * FROM tbl_bill_flow WHERE userId=:userId AND (createTime BETWEEN :timeStart AND :timeEnd) ")
    fun filterDate(timeStart: Long, timeEnd: Long, userId: Long): PagingSource<Int, BillFlowInfo>

    /*根据时间和消费类型取流水*/
    @Query("SELECT * FROM tbl_bill_flow WHERE userId=:userId AND (createTime BETWEEN :timeStart AND :timeEnd) AND typeId IN (:types) ")
    suspend fun filterDateAndTagAsLiveData(
        timeStart: Long,
        timeEnd: Long,
        types: List<Long>,
        userId: Long
    ): List<BillFlowInfo>

    /*只按时间范围取流水数据*/
    @Query("SELECT * FROM tbl_bill_flow WHERE userId=:userId AND (createTime BETWEEN :timeStart AND :timeEnd) ")
    suspend fun filterDateAsLivaData(
        timeStart: Long,
        timeEnd: Long,
        userId: Long
    ): List<BillFlowInfo>

    /*取最新的一条数据的ID*/
    @Query("SELECT flowId FROM tbl_bill_flow ORDER BY flowId DESC LIMIT 1")
    fun obtainLatest(): Long?

    /*添加一条流水*/
    @Insert
    suspend fun addBillFlow(billFlow: BillFlowInfo): Long

    /*取所有流水数据，无任何条件*/
    @Query("SELECT * FROM tbl_bill_flow")
    fun noneFilter(): PagingSource<Int, BillFlowInfo>
}

/*账户数据库*/
@Dao
interface AccountDao {
    /*取当前用户的账户*/
    @Query("SELECT * FROM tbl_account WHERE userId=:userId")
    fun observeAccounts(userId: Long): PagingSource<Int, AccountInfo>

    /*取当前用户的账户*/
    @Query("SELECT * FROM tbl_account WHERE userId=:userId")
    fun queryAccounts(userId: Long): List<AccountInfo>

    /*取用户设置的账户的类型*/
    @Query("SELECT * FROM tbl_account_type WHERE userId = :userId OR userId = 0")
    fun observeAccountTypes(userId: Long): LiveData<List<AccountType>>

    /**
     * 添加初始化的账户类型
     */
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun addTypes(list: List<AccountType>)

    /**
     *取最新的账户信息
     */
    @Query("SELECT * FROM tbl_account ORDER BY accountId DESC LIMIT 1")
    fun obtainLatest(): AccountInfo?

    /*添加用户*/
    @Insert
    suspend fun addAccount(accountInfo: AccountInfo): Long

    /**获取用户的所有账户信息
     *
     */
    @Query("SELECT * FROM tbl_account WHERE userId=:userId")
    fun observeAccountList(userId: Long): LiveData<List<AccountInfo>>

    /**
     * 更新账户金额
     */
    @Query("UPDATE tbl_account SET balance = :remainBalance WHERE userId=:userId AND accountId=:accountId")
    suspend fun updateBalance(userId: Long, accountId: Long, remainBalance: Long)
}
